﻿using System;
using System.Diagnostics;

using Datagility.Shpt.SPDocMirror.Settings;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace Datagility.Shpt.SPDocMirror.Service
{
    /// <summary>
    /// A SharePoint Timer Job definition.
    /// </summary>
    /// <remarks>
    /// The MirrorJob class encapsulates SharePoint's interaction with the DocMirror application.
    /// The JobDefinition has a LockType of 'ContentDatabase' which prevents the job running on
    /// more than 1 WFE server in a farm. If more than one WFE is part of the farm, SharePoint 
    /// only schedules the job to be executed on a single WFE. If that WFE is removed from the farm, 
    /// the job is not scheduled on any other WFE automatically, so the job will no longer be executed 
    /// until 1) the WFE is added back to the farm or 2) the feature that registered the job is 
    /// deactivated and reactivated. See http://blogs.pointbridge.com/Blogs/morse_matt/Pages/Post.aspx?_ID=55
    /// for more details.
    /// </remarks>
    class MirrorJob : SPJobDefinition
    {
        const string DOC_MIRROR_SETTINGS_NAME = "MirrorJobSettings";

        SPSite siteCollection = null;

        public MirrorJob()
            : base()
        {
        }

        public MirrorJob(string jobName, SPService service, SPServer server, SPJobLockType targetType)
            : base(jobName, service, server, targetType)
        {
        }

        public MirrorJob(string jobName, SPWebApplication webApplication)
            : base(jobName, webApplication, null, SPJobLockType.ContentDatabase)
        {
            this.Title = "SPDocMirror Document Library Mirroring";
        }

        /// <summary>
        /// Called by the Windows SharePoint Services Timer (OWSTIMER.EXE) service to check for new audit
        /// log entries and mirror any document changes to the 'shadow folder'
        /// </summary>
        /// <param name="contentDbId">The database ID of the content database being processed 
        /// by the running job</param>
        public override void Execute(Guid contentDbId)
        {
            SPMirrorLoggingService.Write("Information", "MirrorJob.Execute Starting...");

            Processor proc = null;
            try
            {
                //Disable the job just to make certain the job doesn't fire whilst a previous long-running
                // execution is still running.
                this.IsDisabled = true;
                this.Update();

                SPWebApplication webApplication = this.Parent as SPWebApplication;
                //Get a reference to the root Site Collection for the Web App
                siteCollection = webApplication.Sites[0];

                MirrorJobSettings settings = MirrorJobSettingsFactory.GetMirrorJobSettings(siteCollection.Url);

                string shadowRoot = settings.ShadowRoot;
                if (shadowRoot != null)
                {
                    //As long as we have a value for the root 'shadow' folder (from SharePoint's
                    // persisted settings) create a new Processor object, get the time at which the
                    // job last started, record the current start time and process any log entries
                    proc = new Processor(siteCollection);

                    DateTime newStart = DateTime.UtcNow;
                    proc.ProcessChanges(settings);

                    settings.LastRunStart = newStart;
                    MirrorJobSettingsFactory.SetMirrorJobSettings(siteCollection.Url, settings);
                }
                else
                {
                    throw new ApplicationException("No Root Folder Set");
                }
                //If we completed successfully re-enable the job
                this.IsDisabled = false;
                this.Update();
            }
            catch (Exception eX)
            {
                //Note: If we throw an exception here the job will remain disabled.
                SPMirrorLoggingService.Write("Error", eX.ToString());
                throw eX;
            }
            finally
            {
                if (proc != null)
                {
                    proc.Dispose();
                }
                SPMirrorLoggingService.Write("Information", "MirrorJob.Execute Complete");
            }
        }
    }
}
